home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ABUSESRC.ZIP / AbuseSrc / macabuse / imlib / port / x11 / video.c < prev    next >
C/C++ Source or Header  |  1997-05-20  |  20KB  |  794 lines

  1. #include <X11/Xlib.h> 
  2. #include <X11/Xutil.h>
  3. #include <X11/keysym.h>
  4.  
  5. #ifndef NO_XSHM
  6. #include <sys/ipc.h>
  7. #include <sys/shm.h>
  8. #include <X11/extensions/XShm.h>
  9. #include <signal.h>
  10. #endif
  11.  
  12. #include <string.h>
  13. #ifdef _AIX
  14. #include <strings.h>
  15. #endif
  16.  
  17. #include "filter.hpp"
  18. #include "globals.hpp"
  19. #include "system.h"
  20. #include "video.hpp"
  21. #include "dos.h"
  22. #include "xinclude.h"
  23. #include "macs.hpp"
  24. #include "bitmap.h"
  25. #include "image.hpp"
  26. #include "jmalloc.hpp"
  27.  
  28. unsigned char current_background;
  29.  
  30. extern unsigned long xres, yres;
  31. extern palette *lastl;
  32. int X_xoff,Y_yoff,vmode;
  33. image *screen;
  34. char display_name[120];
  35.  
  36. Window root;
  37. Display *display;
  38. int screen_num;
  39. Screen *screen_ptr;
  40. unsigned border_width,depth;
  41. Colormap XCMap;
  42. Window mainwin;
  43. GC gc;
  44. XFontStruct *font_info;
  45. XVisualInfo *my_visual;
  46. Visual *X_visual;
  47.  
  48. uchar last_load_palette[256*4];  // store word alligned for faster access
  49.  
  50.  
  51.  
  52.  
  53. // ========================================================================
  54. // makes a null cursor
  55. // ========================================================================
  56.  
  57. static Cursor CreateNullCursor(Display *display, Window root)
  58. {
  59.     Pixmap cursormask; 
  60.     XGCValues xgc;
  61.     GC gc;
  62.     XColor dummycolour;
  63.     Cursor cursor;
  64.  
  65.     cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/);
  66.     xgc.function = GXclear;
  67.     gc =  XCreateGC(display, cursormask, GCFunction, &xgc);
  68.     XFillRectangle(display, cursormask, gc, 0, 0, 1, 1);
  69.     dummycolour.pixel = 0;
  70.     dummycolour.red = 0;
  71.     dummycolour.flags = 04;
  72.     cursor = XCreatePixmapCursor(display, cursormask, cursormask,
  73.           &dummycolour,&dummycolour, 0,0);
  74.     XFreePixmap(display,cursormask);
  75.     XFreeGC(display,gc);
  76.     return cursor;
  77. }
  78.  
  79.  
  80.  
  81. #ifndef NO_SHM
  82. // ************** SHM Vars *******************
  83. int shm_base,shm_error_base,shm_finish_event,doShm=0,do24=0;
  84.  
  85.  
  86. struct event_node
  87. {
  88.   XEvent report;  
  89.   event_node *next;  
  90. } ;
  91.  
  92.  
  93. void wait_shm_finish()
  94. {
  95.   event_node *en,*first=NULL;
  96.   while (1)
  97.   { 
  98.     en=(event_node *)jmalloc(sizeof(event_node),"shm_wait : event");
  99.     XNextEvent(display, &en->report);
  100.  
  101.     // if this is the finishing event, put all the stored events back
  102.     // on the que
  103.     if (en->report.type==shm_base+ShmCompletion)
  104.     {
  105.       jfree(en);
  106.       
  107.       while (first)
  108.       {
  109.     XPutBackEvent(display,&first->report);
  110.     en=first;
  111.     first=first->next;
  112.     jfree(en);    
  113.       }
  114.       return ;      
  115.     } else // put the event on the que to be puback
  116.     {
  117.       en->next=first;     // put the back in reverse order
  118.       first=en;
  119.     }    
  120.   }
  121. }
  122.  
  123.     
  124. #endif
  125.  
  126.  
  127. int get_vmode()
  128. { return vmode; }
  129.  
  130. void getGC(Window win, GC *gc, XFontStruct *font_info)
  131. {
  132.   XGCValues values;
  133.   *gc=XCreateGC(display,win,0,&values);
  134.   XSetFont(display, *gc, font_info->fid);
  135.   XSetForeground(display, *gc, BlackPixel(display,screen_num));
  136.   XSetLineAttributes(display, *gc, 1, LineSolid, CapRound, JoinRound);
  137. }
  138.  
  139.  
  140. class XImage_Info             // stored in the extended desciptor
  141. {
  142. public :
  143.   
  144. #ifndef NO_SHM
  145.   XShmSegmentInfo X_shminfo;    
  146. #endif
  147.   XImage *XImg;
  148. } ;
  149.  
  150.  
  151. void image::make_page(short width, short height, unsigned char *page_buffer)
  152. {
  153.   XImage_Info *xi;  
  154.   if (special && !special->static_mem)
  155.   {
  156.     xi=new XImage_Info;
  157.     special->extended_descriptor=(void *)xi;    
  158. #ifndef NO_SHM
  159.     if (doShm)
  160.     {
  161.       width=(width+3)&(0xffffffff-3);
  162.       // create the image
  163.       xi->XImg = XShmCreateImage(display,
  164.                  X_visual,
  165.                  my_visual->depth,
  166.                  ZPixmap,
  167.                  0,
  168.                  &xi->X_shminfo,
  169.                  do24 ? width*2 : width,
  170.                  do24 ? height*2 : height );
  171.  
  172.       w=width=xi->XImg->bytes_per_line/(do24 ? 2 : 1);  // adjust image size to X requirments
  173.       
  174.       
  175.       // create the shared memory segment
  176.       xi->X_shminfo.shmid = shmget (IPC_PRIVATE, do24 ? width*height*4 : width*height, IPC_CREAT | 0777);
  177.       ERROR(xi->X_shminfo.shmid>=0,"shmget() failed, go figure");
  178.  
  179.       xi->X_shminfo.readOnly=False;
  180.       
  181.  
  182.       // attach to the shared memory segment to us
  183.       xi->XImg->data = xi->X_shminfo.shmaddr =
  184.         (char *) shmat(xi->X_shminfo.shmid, 0, 0);
  185.       ERROR(xi->XImg->data,"shmat() failed, go figure");
  186.  
  187.  
  188.       // get the X server to attach to it to the X server
  189.       ERROR(XShmAttach(display, &xi->X_shminfo),"XShmAttach() failed, go figure");
  190.       XSync(display,False); // make sure segment gets attached
  191.       ERROR(shmctl(xi->X_shminfo.shmid,IPC_RMID,NULL)==0,"shmctl failed, why?"); 
  192.  
  193.       if (do24)
  194.         data=(uchar *)jmalloc(width*height,"24 bit image data");
  195.       else data=(unsigned char *) (xi->XImg->data);
  196.  
  197.     } else 
  198. #endif
  199.     {
  200.       width=(width+3)&(0xffffffff-3);        
  201.       if (!page_buffer)
  202.         page_buffer=(unsigned char *)jmalloc(do24 ? width*height*4 : width*height,"image::data");
  203.       
  204.       xi->XImg = XCreateImage(    display,
  205.                     X_visual,
  206.                     my_visual->depth,
  207.                     ZPixmap,
  208.                     0,
  209.                     (char *)page_buffer,
  210.                     do24 ? width*2  : width, 
  211.                     do24 ? height*2 : height,
  212.                     32,
  213.                     0 );
  214.       ERROR(xi->XImg,"XCreateImage failed");
  215.  
  216.       w=width=(xi->XImg->bytes_per_line/(do24 ? 2 : 1));  // adjust image size to X requirments
  217.  
  218.       if (do24)
  219.         data=(uchar *)jmalloc(width*height,"24 bit image data");
  220.       else data=(unsigned char *) (xi->XImg->data);
  221.     }    
  222.   }
  223.   else 
  224.   {
  225.     if (!page_buffer)
  226.       data=(unsigned char *)jmalloc(width*height,"image::data");
  227.     else data=page_buffer;
  228.   }
  229.  
  230.   if (special)
  231.     special->resize(width,height);
  232. }
  233.  
  234.  
  235.  
  236.  
  237. void image::delete_page()
  238.   XImage_Info *xi;  
  239.   if (special && !special->static_mem && special->extended_descriptor)
  240.   {    
  241.     xi=(XImage_Info *)special->extended_descriptor;    
  242. #ifndef NO_SHM
  243.     if (doShm)
  244.     {    
  245.       XFlush(display);
  246.       XSync(display,False);  // maker sure anything with this image is drawn!
  247.  
  248.       // Dettach the memory from the server
  249.       ERROR(XShmDetach(display, &xi->X_shminfo),"XShmDetach() failed, go figure");
  250.  
  251.       XSync(display,False);  // maker sure server detached
  252.  
  253.       // detach the memory from us, it will be deleted!
  254.       ERROR(shmdt(xi->X_shminfo.shmaddr)>=0,"shmdt failed, oops");
  255.  
  256.       xi->XImg->data=NULL;  // tell X not to try to free the memory, cause we already did.
  257.  
  258.       XDestroyImage(xi->XImg);    
  259.  
  260.       if (do24)         // if 24 bit, we need to free addition "real" page 
  261.         jfree(data);
  262.  
  263.     } else
  264. #endif
  265.     {
  266.       if (!special->static_mem)
  267.         jfree(xi->XImg->data);
  268.       xi->XImg->data=NULL;                  // make sure X doesn't try to free static memory
  269.       XDestroyImage(xi->XImg);    
  270.  
  271.       if (do24)         // if 24 bit, we need to free addition "real" page 
  272.         jfree(data);
  273.     }
  274.     delete xi;
  275.   }
  276.   else if (!special)
  277.     jfree(data);      
  278. }
  279.  
  280.  
  281. #ifndef NO_SHM
  282. #ifdef __sgi
  283. void clean_shm(...)
  284. #else
  285. void clean_shm(int why)      // on exit, delete all images, so shm get de-allocated.
  286. #endif
  287. {
  288.   while (image_list.first())
  289.   {
  290.     image *i=(image *)image_list.first();
  291.     delete i;
  292.   }
  293. }
  294. #endif
  295.  
  296. void set_mode(video_mode mode, int argc, char **argv)
  297. {
  298.   unsigned char *page;
  299.   vmode=mode;
  300.   XVisualInfo vis_info;
  301.   int items,i;
  302.   XEvent report;
  303.   XWMHints *wm_hints;
  304.   XClassHint *class_hints;
  305.   XTextProperty winName,iconName;
  306.   XSizeHints *size_hints;
  307.   char *win_name=argv[0],        // name the window and the icon the executable name
  308.        *icon_name=argv[0];
  309.   Pixmap icon_pixmap;
  310.   
  311.   // get the default display name from the enviroment variable DISPLAY
  312.   char *ds_name=getenv("DISPLAY");
  313.   if (!ds_name) ds_name="unix:0.0";
  314.   strcpy(display_name,ds_name); 
  315.  
  316.   int suppress_shm=0;
  317.  
  318.   // check for command line display name
  319.   for (i=1;i<argc;i++)
  320.   {
  321.     if (!strcasecmp(argv[i],"-display") || !strcasecmp(argv[i],"-disp"))
  322.     {
  323.       i++;      
  324.       strcpy(display_name,argv[i]);  
  325.     }    
  326.     else if (!strcasecmp(argv[i],"-noshm"))
  327.       suppress_shm=1;
  328.     else if (!strcasecmp(argv[i],"-24bit"))
  329.       do24=1;
  330.   }
  331.     
  332.   display=XOpenDisplay(display_name);  
  333.   if (!display)
  334.   {
  335.     printf("Cound not connect to X server named '%s'\n",display_name);
  336.     exit(1);
  337.   }
  338.  
  339. #ifndef NO_SHM
  340.   // check for the MITSHM extension
  341.   int major_op;
  342.   
  343.   if (suppress_shm)
  344.     doShm=0;
  345.   else
  346.     doShm = XQueryExtension(display,"MIT-SHM",&major_op,&shm_base,&shm_error_base);
  347.  
  348.   // make sure it's a local connection
  349.   if (doShm)
  350.   {    
  351.     char *d = display_name;
  352.     while (*d && (*d != ':')) d++;
  353.     if (*d) *d = 0;
  354.     if (strcasecmp(display_name, "unix") && display_name[0]!=0) 
  355.       doShm = 0;   
  356.   }
  357.  
  358.   if (doShm)
  359.   {
  360.     printf("Using MITSHM extension!\n");
  361.     int sigs[29]={SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGTRAP,
  362.         SIGABRT,SIGIOT,SIGBUS,SIGFPE,SIGKILL,
  363.         SIGUSR1,SIGSEGV,SIGUSR2,SIGPIPE,SIGALRM,
  364.                 SIGTERM,SIGCHLD,SIGCONT,SIGSTOP,
  365.         SIGTSTP,SIGTTIN,SIGTTOU,SIGIO,
  366.         SIGURG,SIGXCPU,SIGXFSZ,SIGVTALRM,SIGPROF,
  367.         SIGWINCH};
  368.  
  369.     for (int i=0;i<29;i++)
  370.       signal(sigs[i],clean_shm);
  371.   }
  372. #endif
  373.   depth=do24 ? 24 : 8;
  374.   screen_num = DefaultScreen(display);
  375.   screen_ptr = DefaultScreenOfDisplay(display);
  376.   unsigned int lxres=xres,lyres=yres;
  377.   ERROR(XGetGeometry(display,RootWindow(display,screen_num), &root,
  378.     &X_xoff,&Y_yoff,&lxres,&lyres,&border_width,&depth),
  379.     "can't get root window attributes");
  380.   xres=lxres;
  381.   yres=lyres;
  382.  
  383.   {
  384.     vis_info.c_class=PseudoColor;       
  385.     vis_info.depth=8;
  386.     my_visual=XGetVisualInfo(display,VisualClassMask | VisualDepthMask, &vis_info,&items);
  387.     X_visual=my_visual->visual;
  388.  
  389.     if (items>0)
  390.     {
  391.       int rc;
  392.  
  393.  
  394.       rc=XMatchVisualInfo(display, screen_num, 8, PseudoColor, &vis_info);
  395.       ERROR(rc, "What the hell? Non-8 bit Psuedo color..\n");
  396.       X_visual = my_visual->visual = vis_info.visual;
  397.       //    ERROR(my_visual->depth==8,"What the hell? Non-8 bit Psuedo color..\n");
  398.       printf("Using 8 bit Psuedo color\n");
  399.     }
  400.     else
  401.     { 
  402.       printf("X windows screen type not supported\n");
  403.       exit(0); 
  404.     }
  405.   }
  406.  
  407.   switch (mode)
  408.   {
  409.     case VMODE_320x200 : 
  410.     { xres=320; yres=200; } break;
  411.     case VMODE_640x480 :
  412.     { xres=640; yres=480; } break;
  413.       
  414.   }
  415.  
  416.   for (i=1;i<argc;i++)
  417.   { if (!strcmp(argv[i],"-size"))
  418.     { i++; if (!sscanf(argv[i],"%d",&xres)) xres=320;
  419.       i++; if (!sscanf(argv[i],"%d",&yres)) yres=200;
  420.     }
  421.   }
  422.  
  423.  
  424.   Colormap tmpcmap;
  425.   
  426.   tmpcmap = XCreateColormap(display, XRootWindow(display,
  427.                         my_visual->screen), X_visual, AllocNone);
  428.  
  429.   int attribmask = CWColormap | CWBorderPixel;
  430.   XSetWindowAttributes attribs;
  431.   attribs.border_pixel = 0;
  432.   attribs.colormap = tmpcmap;
  433.   
  434.   mainwin=XCreateWindow(display,
  435.             XRootWindow(display,my_visual->screen),
  436.             0,0,do24 ? xres*2 : xres,do24 ? yres*2 : yres,
  437.             0,
  438.             my_visual->depth,
  439.             InputOutput,
  440.             X_visual,
  441.             attribmask,
  442.             &attribs);
  443.   xres--; yres--;
  444.  
  445.  
  446.   icon_pixmap=XCreateBitmapFromData(display,mainwin,bitmap_bits,
  447.     bitmap_width, bitmap_height);
  448.   ERROR((size_hints=XAllocSizeHints()),"memory allocation error");
  449.   ERROR((wm_hints=XAllocWMHints()),"memory allocation error");
  450.   ERROR((class_hints=XAllocClassHint()),"memory allocation error");
  451.  
  452.   int lock=0;
  453.   for (i=1;i<argc;i++)
  454.     if (!strcmp(argv[i],"-lock_size"))
  455.      lock=1;
  456.  
  457.   if (lock)
  458.   {
  459.     size_hints->flags=PPosition | PSize | PMinSize | PMaxSize;
  460.     size_hints->min_width  = xres+1;
  461.     size_hints->min_height = yres+1;
  462.     size_hints->max_width  = xres+1;
  463.     size_hints->max_height = yres+1;
  464.   }
  465.   else
  466.   {
  467.     size_hints->flags=PPosition | PSize | PMinSize;
  468.     size_hints->min_width  = 320;
  469.     size_hints->min_height = 200;
  470.   }
  471.  
  472.  
  473.   ERROR(XStringListToTextProperty(&win_name,1,&winName),"alloc failed");
  474.   ERROR(XStringListToTextProperty(&icon_name,1,&iconName),"alloc fialed");
  475.   wm_hints->initial_state=NormalState;  // not iconified at first
  476.   wm_hints->input=1;                  // needs keyboard input
  477.   wm_hints->icon_pixmap=icon_pixmap;
  478.   wm_hints->flags=StateHint | IconPixmapHint | InputHint;
  479.   class_hints->res_name=argv[0];
  480.   class_hints->res_class="(C) 1995 Crack dot Com, Jonathan Clark";
  481.   XSetWMProperties(display,mainwin,&winName,&iconName,argv,argc,size_hints,
  482.     wm_hints,class_hints);
  483.  
  484.   XSelectInput(display,mainwin,
  485.     KeyPressMask | VisibilityChangeMask | ButtonPressMask | ButtonReleaseMask |
  486.     ButtonMotionMask | PointerMotionMask | KeyReleaseMask |
  487.     ExposureMask | StructureNotifyMask);
  488.  
  489.   ERROR(font_info=XLoadQueryFont(display,"9x15"),"cannot open 9x15");
  490.   getGC(mainwin,&gc,font_info);
  491.  
  492. /* try to determine what type of monitor we are using */
  493.  
  494.  
  495.   // detect which type of screen the X client will run on...
  496.   // if they requested 24 bit mode, check for that type of display
  497.  
  498.  
  499.  
  500.   XSetBackground(display,gc,BlackPixel(display,screen_num));
  501.  
  502.   XMapWindow(display,mainwin);
  503.   do
  504.   { XNextEvent(display, &report);
  505.   } while (report.type!= Expose);     // wait for our window to pop up
  506.  
  507.  
  508.   XDefineCursor(display,mainwin, CreateNullCursor(display,mainwin));
  509.  
  510.   screen=new image(xres+1,yres+1,NULL,2);  
  511.  
  512.   XCMap=XCreateColormap(display,mainwin,X_visual,AllocAll);  
  513.   screen->clear();
  514.   update_dirty(screen);
  515.  
  516.   for (i=1;i<argc;i++)
  517.   { if (!strcmp(argv[i],"-grab_pointer"))
  518.     {
  519.       i++;
  520.       int sec;
  521.       if (i<argc && sscanf(argv[i],"%d",&sec))
  522.       { printf("-grab_pointer : delaying for %d seconds\n",sec);
  523.     sleep(sec);
  524.       }
  525.       if (XGrabPointer(display,mainwin,True,
  526.                PointerMotionMask|ButtonMotionMask|
  527.                Button1MotionMask|
  528.                Button2MotionMask|
  529.                Button3MotionMask|
  530.                Button4MotionMask|
  531.                Button5MotionMask,
  532.                GrabModeAsync,
  533.                GrabModeAsync,
  534.                mainwin,
  535.                None,
  536.                CurrentTime)==GrabSuccess)
  537.         printf("Pointer grab in effect!\n");
  538.       else
  539.         printf("Unable to grab pointer  :(\n");
  540.     }
  541.   }
  542.     
  543. }
  544.  
  545. void close_graphics()
  546. {
  547.   if (lastl) delete lastl; lastl=NULL;
  548.   if (screen)
  549.     delete screen;
  550.   XUnloadFont(display,font_info->fid);
  551.   XFreeGC(display,gc);
  552.   XFree((char *)my_visual);
  553.   XCloseDisplay(display);
  554. }
  555.  
  556. void copy_24part(uchar *Xdata, image *im, int x1, int y1, int x2, int y2)
  557. {
  558.   uchar *src=im->scan_line(y1)+x1;
  559.   ushort *dst=(ushort *)Xdata+(y1*2)*im->width()+x1;
  560.  
  561.   int src_add=im->width()-(x2-x1+1);
  562.  
  563.   int x,y,w=(x2-x1+1)*2;
  564.   ushort v;
  565.   for (y=y1;y<=y2;y++)
  566.   {
  567.     for (x=x1;x<=x2;x++)
  568.     {
  569.       v=*(src++);
  570.       *(dst++)=(v|(v<<8));
  571.     }    
  572.     dst=(ushort *) ((uchar *)dst+src_add*2);
  573.     memcpy(dst,(uchar *)dst-im->width()*2,w);
  574.     dst=(ushort *)((uchar *)dst+im->width()*2);
  575.  
  576.     src+=src_add;
  577.   }
  578. }
  579.  
  580.  
  581.  
  582. void put_part_image(Window win, image *im, int x, int y, int x1, int y1, int x2, int y2)
  583. {
  584.   CHECK(im->special);
  585.   XImage_Info *xi=(XImage_Info *)im->special->extended_descriptor;
  586.  
  587.   if (do24)
  588.     copy_24part((uchar *)xi->XImg->data,im,x1,y1,x2,y2);
  589.  
  590. #ifndef NO_SHM
  591.   if (doShm)
  592.   {    
  593.     XEvent ev;
  594.     XSync(display,False);
  595.     if (XCheckTypedEvent(display, ConfigureNotify,&ev)==False)
  596.     {
  597.       if (do24)
  598.         XShmPutImage(display,win,gc,xi->XImg,x1*2,y1*2,x*2,y*2,(x2-x1+1)*2,(y2-y1+1)*2,True);
  599.       else
  600.         XShmPutImage(display,win,gc,xi->XImg,x1,y1,x,y,x2-x1+1,y2-y1+1,True);
  601.       // wait for the Put to finish
  602.       wait_shm_finish();
  603.     } else     // screen size changed,  better wait till this event is handled cause put might be invalid
  604.       XPutBackEvent(display,&ev);
  605.  
  606.   }  
  607.   else  
  608. #endif
  609.   if (do24)
  610.     XPutImage(display,win,gc,xi->XImg,x1*2,y1*2,x*2,y*2,(x2-x1+1)*2,(y2-y1+1)*2);
  611.   else
  612.     XPutImage(display,win,gc,xi->XImg,x1,y1,x,y,x2-x1+1,y2-y1+1);
  613.  
  614. }
  615.  
  616. void put_image(image *im, int x, int y)
  617. {
  618.   put_part_image(mainwin,im,x,y,0,0,im->width()-1,im->height()-1);  
  619. }
  620.  
  621.  
  622.  
  623. void update_dirty_window(Window win, image *im, int xoff, int yoff)
  624. {
  625.  
  626.   int count;
  627.   dirty_rect *dr,*q;
  628.   image *Xim;
  629.   CHECK(im->special);  // make sure the image has the ablity to contain dirty areas
  630.   if (im->special->keep_dirt==0)
  631.     put_image(im,xoff,yoff);
  632.   else
  633.   {
  634.     count=im->special->dirties.number_nodes();
  635.     if (!count) return;  // if nothing to update, return
  636.     dr= (dirty_rect *) (im->special->dirties.first());
  637.     while (count>0)
  638.     {
  639.       put_part_image(win,im,xoff+dr->dx1,yoff+dr->dy1,dr->dx1,dr->dy1,dr->dx2,dr->dy2);     
  640. //      XDrawRectangle(display,mainwin,gc,xoff+dr->dx1,yoff+dr->dy1,
  641. //             xoff+dr->dx2-dr->dx1+1,yoff+dr->dy2-dr->dy1+1);
  642.       q=dr;
  643.       dr=(dirty_rect *) (dr->next());
  644.       im->special->dirties.unlink((linked_node *)q);
  645.       delete q;
  646.       count--;
  647.     }
  648.   }
  649. //  XFlush(display);
  650. }
  651.  
  652. void update_dirty(image *im, int xoff, int yoff)
  653. { update_dirty_window(mainwin,im,xoff,yoff); }
  654.  
  655. void palette::load()
  656. {
  657.   if (lastl)
  658.     delete lastl;
  659.   lastl=copy();
  660.  
  661.   {
  662.     int i;
  663.  
  664.       XColor color;
  665.       color.flags=DoRed|DoBlue|DoGreen;
  666.       for (i=0;i<ncolors;i++)
  667.       {
  668.     color.pixel=i;
  669.     color.red=red(i)<<8|0xff; color.green=green(i)<<8|0xff; color.blue=blue(i)<<8|0xff;
  670.     XStoreColor(display,XCMap,&color);
  671.       }
  672.       XSetWindowColormap(display,mainwin,XCMap);
  673.  
  674.     current_background=bg;
  675.   }
  676. }
  677.  
  678. struct hist_entry
  679. {
  680.   long total;
  681.   unsigned char org;
  682. } ;
  683.  
  684. static int histcompare(const void *i, const void *j)
  685.   if (((hist_entry *)i)->org==0) return -1;  // make sure the background gets allocated
  686.   else return(((hist_entry *)j)->total - ((hist_entry *)i)->total); 
  687. }
  688.  
  689.  
  690. void palette::load_nice()
  691. {
  692.   int i,fail,y,x,wd,j;
  693.   long closest_val,closest_pixel,k;
  694.   char *gotten;
  695.   image *im;
  696.   unsigned char *sl;
  697.   palette *Xpal;
  698.   hist_entry *histogram;
  699.   Colormap stdcm;
  700.   XColor color;
  701.  
  702.   if (do24) { load(); return ; }
  703.  
  704.   filter f(ncolors);
  705.  
  706.   histogram=(hist_entry *)jmalloc(sizeof(hist_entry)*ncolors,"palette::histogram"); 
  707.   gotten=(char *)jmalloc(ncolors,"palette::gotten_colors");
  708.  
  709.   memset(gotten,0,ncolors);
  710.   for (i=0;i<ncolors;i++)
  711.   { histogram[i].total=0;
  712.   histogram[i].org=i;
  713.   }
  714.  
  715.   for (i=image_list.number_nodes(),im=(image *)image_list.first();i;i--,im=(image *)im->next()) 
  716.   { 
  717.     if (im!=screen)
  718.     { 
  719.       wd=im->width();
  720.       for (y=im->height();y;y--)
  721.       {
  722.         sl=im->scan_line(y-1);
  723.         for (x=0;x<wd;x++)
  724.           histogram[sl[x]].total++;
  725.       }
  726.     }
  727.   }
  728.   qsort(histogram,ncolors,sizeof(hist_entry),histcompare);
  729.   stdcm=XDefaultColormap(display,screen_num);
  730.   Xpal=NULL;
  731.   for (i=0,fail=0;i<ncolors;i++)
  732.   {
  733.     color.red=red(histogram[i].org)<<8; 
  734.     color.green=green(histogram[i].org)<<8; 
  735.     color.blue=blue(histogram[i].org)<<8; 
  736.  
  737.     if (XAllocColor(display,stdcm,&color))
  738.       f.set(histogram[i].org,color.pixel);
  739.     else  // if we couldn't allocate that color from X, find the closest.
  740.     {
  741.       if (!Xpal)
  742.       { Xpal=new palette(ncolors);
  743.       for (j=0;j<ncolors;j++)
  744.       {
  745.         color.pixel=j;
  746.         XQueryColor(display,stdcm,&color);
  747.         Xpal->set(j,color.red>>8,color.green>>8,color.blue>>8);
  748.       }
  749.       }
  750.       closest_val=0xfffffff;
  751.       for (j=0;j<ncolors;j++)
  752.       {
  753.         k=Xpal->red(j)*Xpal->red(j)+Xpal->green(j)*Xpal->green(j)+
  754.           Xpal->blue(j)*Xpal->blue(j);
  755.         if (k<closest_val)
  756.         { closest_val=k;
  757.         closest_pixel=j;
  758.         }
  759.       }
  760.       f.set(histogram[i].org,closest_pixel);
  761.     }
  762.   }
  763.   if (!Xpal)
  764.     Xpal=new palette(ncolors);
  765.   // store the color mapping we created back to the palette.
  766.   for (j=0;j<ncolors;j++)
  767.     Xpal->set(j,red(f.get_mapping(j)),green(f.get_mapping(j)),blue(f.get_mapping(j)));
  768.   for (j=0;j<ncolors;j++)
  769.     set(j,Xpal->red(j),Xpal->green(j),Xpal->blue(j));  
  770.   bg=f.get_mapping(bg);
  771.       
  772.   // now remap all the images to fit this colormap!
  773.   for (i=image_list.number_nodes(),im=(image *)image_list.first();i;i--,im=(image *)im->next()) 
  774.     f.apply(im);
  775.  
  776.   delete Xpal;
  777.   jfree(histogram);
  778.   jfree(gotten);
  779.  
  780.   current_background=bg;
  781. }
  782.  
  783.  
  784. void switch_mode(video_mode new_mode)
  785. {
  786.   close_graphics();
  787.   char *argv[]= {"Game","-noshm"};
  788.   
  789.   set_mode(new_mode,2,argv);
  790. }
  791.  
  792.